/************************************************************************

								Heroes IV
					  Copyright 2002, The 3DO Company

	------------------------------------------------------------------
  						      dialog_booty.cpp

	$Header: $

	$NoKeywords: $

 ************************************************************************/

#include "precompiled.h"

#include "dialog_booty.h"

#include <stdlib.h>

#include "adaptor_handler.h"
#include "artifact.h"
#include "artifact_slot.h"
#include "bitmap_group_cache.h"
#include "bound_handler.h"
#include "button.h"
#include "button_cache.h"
#include "creature_array.h"
#include "creature_array_window.h"
#include "creature_stack.h"
#include "drag_artifact.h"
#include "format_string.h"
#include "external_string.h"
#include "interface_help.h"
#include "minimum_maximum.h"
#include "report_combat_results.h"
#include "standard_fonts.h"
#include "text_window.h"

extern t_button_cache g_ok_button;
static t_button_cache const k_artifact_frame_44_button( "button.frame_44" );

namespace
{
	t_bitmap_group_cache const k_bitmaps( "dialog.booty" );

	class t_holding_drag_artifact : public t_drag_artifact
	{
		public:
			t_holding_drag_artifact( t_artifact const& artifact, t_drag_artifact_source* source, t_dialog_booty * parent );

		private:
			t_counted_ptr< t_dialog_booty > m_parent;

	};

	t_holding_drag_artifact::t_holding_drag_artifact( t_artifact const& artifact, t_drag_artifact_source* source, t_dialog_booty * parent )
		: t_drag_artifact( artifact, source ), m_parent( parent )
	{

	}
};


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
t_dialog_booty::t_dialog_booty( t_window * parent,
								t_creature_array & winners,
								t_artifact_list & booty,
								std::string const & title,
								std::string const & text )
	: t_window( k_completely_transparent, parent ), m_booty( booty ), m_winners( winners )
{
	m_booty_display_start = 0;
	m_current_drag_index = -1;

	assert( m_booty.size() );
	assert( !m_winners.empty() );

	m_bitmaps = k_bitmaps.get();
	t_help_block const& help = get_help_block( "booty" );

	t_bitmap_layer const * layer;
	t_window *             background;
	t_text_window *		   text_window;
	t_button *             button;

	layer = m_bitmaps->find( "background" );
	background = new t_bitmap_layer_window( layer, t_screen_point(0, 0), this );

	layer = m_bitmaps->find( "title" );
	text_window = new t_text_window( get_font( 20 ), layer->get_rect(), background, title, t_pixel_24(0,0,0) );
	text_window->set_drop_shadow( false );
	text_window->set_justification( k_justify_center );

	layer = m_bitmaps->find( "text" );
	text_window = new t_text_window( get_font( 16 ), layer->get_rect(), background, text, t_pixel_24(0,0,0) );
	text_window->set_drop_shadow( false );
	text_window->set_justification( k_justify_center );

	layer = m_bitmaps->find( "ok_button" );
	button = new t_button( g_ok_button.get(), layer->get_rect().top_left(), background );
	button->set_click_handler( discard_argument< t_button * >( bound_handler( *this, &t_dialog_booty::ok_clicked ) ) );
	set_help( button, help, "ok" );

	layer = m_bitmaps->find( "creature_rings" );
	m_winners_window = new t_creature_array_window( layer->get_rect().top_left(), &m_winners, 
													t_creature_array_window::k_single_row,
													0, background );
	m_winners_window->set_allow_drags( false );

	int const displayed_booty = minimum<int>( k_max_displayed_booty, m_booty.size() );

	// Display middle not ends if less than 5 artifacts
	// Slots which are visible for each possible value of displayed_booty
	static bool const k_display_slots[ k_max_displayed_booty ][ k_max_displayed_booty ] =
	{
		{ false, false, true,  false, false },
		{ false, true,  false, true,  false },
		{ false, true,  true,  true,  false },
		{ false, true,  true,  true,  true  },
		{ true,  true,  true,  true,  true  },
	};

	int i;
	t_cached_ptr< t_button_bitmaps > frame_bitmaps = k_artifact_frame_44_button.get();
	t_screen_rect icon_rect = frame_bitmaps->find( "icon" )->get_rect();
	t_bitmap_layer * unhighlighted_frame = frame_bitmaps->find( "released" );
	t_bitmap_layer * highlighted_frame = frame_bitmaps->find( "highlighted" );

	for (i = 0; i < k_max_displayed_booty; i++)
	{
		if ( k_display_slots[displayed_booty - 1][i] )
		{
			std::string name = format_string( "icon_%i", i + 1 );

			t_screen_rect rect = m_bitmaps->find( name )->get_rect();
			m_booty_display[i].frame = new t_bitmap_layer_window( unhighlighted_frame, rect.top_left(), background );
			m_booty_display[i].highlighted_frame = new t_bitmap_layer_window( highlighted_frame, rect.top_left(), background );
			m_booty_display[i].window = new t_drag_artifact_source( rect + icon_rect.top_left(), k_artifact_slot_none, 
																	this, background );
		}
	}

	if ( m_booty.size() > k_max_displayed_booty )
	{
		m_scroll_left_button = create_button( m_bitmaps, "left", background );
		m_scroll_left_button->set_click_handler( discard_argument< t_button * >( bound_handler( *this, &t_dialog_booty::scroll_left ) ) );
	 	set_help( m_scroll_left_button, help, "scroll_left" );
		
		m_scroll_right_button = create_button( m_bitmaps, "right", background );
		m_scroll_right_button->set_click_handler( discard_argument< t_button * >( bound_handler( *this, &t_dialog_booty::scroll_right ) ) );
	 	set_help( m_scroll_left_button, help, "scroll_right" );
	}

	t_screen_rect rect = m_bitmaps->get_rect();
	rect += (get_parent()->get_client_rect().size() - rect.size()) / 2;
	init( rect );

	update_booty_display();
}

// ---------------------------------------------------------------------------
// Make sure any drag we started ends before we go away
// ---------------------------------------------------------------------------
void t_dialog_booty::on_close()
{
	// Note this must be done no later than this, but this may already
	// be too late because of dependencies on other peer windows or
	// resources managed by the parent.  In that case, call cancel_drag 
	// somewhere earlier in the parent's shutdown chain
	cancel_drag();
}

// ---------------------------------------------------------------------------
// OK: distribute remaining artifacts to first hero (or creature), then close
// the dialog
// ---------------------------------------------------------------------------
void t_dialog_booty::ok_clicked()
{
	if ( m_booty.size() > 0 )
	{
		auto_distribute_booty( m_winners, m_booty );
	}

	close();
}

// ---------------------------------------------------------------------------
// Scroll left
// ---------------------------------------------------------------------------
void t_dialog_booty::scroll_left()
{
	if ( m_booty_display_start > 0 )
	{
		m_booty_display_start--;
		update_booty_display();
	}
}


// ---------------------------------------------------------------------------
// Scroll right
// ---------------------------------------------------------------------------
void t_dialog_booty::scroll_right()
{
	if ( m_booty_display_start + k_max_displayed_booty < m_booty.size() )
	{
		m_booty_display_start++;
		update_booty_display();
	}
}

// ---------------------------------------------------------------------------
// Redisplay the artifacts
// ---------------------------------------------------------------------------
void t_dialog_booty::update_booty_display()
{
	if ( m_booty.empty() )
	{
		// All done
		close();
		return;
	}

	m_booty_display_start = minimum( m_booty_display_start, maximum<int>( m_booty.size() - k_max_displayed_booty, 0 ) );

	int booty_index = m_booty_display_start;
	int i;

	for (i = 0; i < k_max_displayed_booty; i++)
	{
		if ( m_booty_display[i].window )
		{
			bool highlight_frame = false;
			if ( booty_index >= m_booty.size() || booty_index == m_current_drag_index )
			{
    			m_booty_display[i].window->set( t_artifact(), NULL, 0 );

				if ( booty_index >= m_booty.size() )
				{
					m_booty_display[i].booty_index = -1;
				}
				else
				{
					m_booty_display[i].booty_index = m_current_drag_index;
					highlight_frame = true;
				}
			}
			else
			{
    			m_booty_display[i].window->set( m_booty[booty_index], NULL, 0 );
				m_booty_display[i].booty_index = booty_index;
			}

			m_booty_display[i].frame->set_visible( !highlight_frame );
			m_booty_display[i].highlighted_frame->set_visible( highlight_frame );

			booty_index++;
		}
	}

	if ( m_scroll_left_button != NULL )
		m_scroll_left_button->set_visible( m_booty.size() > k_max_displayed_booty );

	if ( m_scroll_right_button != NULL )
		m_scroll_right_button->set_visible( m_booty.size() > k_max_displayed_booty );
}

// ---------------------------------------------------------------------------
// Called by t_drag_artifact_source when an artifact is dragged onto a
// different slot. We don't allow user to swap artifacts around, so do nothing
// ---------------------------------------------------------------------------
void t_dialog_booty::accept_artifact_drag( t_drag_artifact* drag, t_drag_artifact_source* dest )
{
	return;
}

// ---------------------------------------------------------------------------
// Called by t_drag_artifact_source when an artifact is first dragged to
// set up the drag.
// ---------------------------------------------------------------------------
void t_dialog_booty::begin_artifact_drag( t_drag_artifact_source* source )
{
	// Which slot is this?
	int source_index = 0;

	while ( source_index < k_max_displayed_booty && source != m_booty_display[source_index].window )
		source_index++;

	if ( source_index == k_max_displayed_booty )
	{
		assert( false );
		return;
	}

	m_current_drag_index = m_booty_display[source_index].booty_index;

	t_drag_artifact* drag = new t_holding_drag_artifact( m_booty[m_current_drag_index], source, this );

	begin_drag( drag );

	update_booty_display();
}

// ---------------------------------------------------------------------------
// Called by t_drag_artifact_source when an artifact is dropped without
// being accept
// ---------------------------------------------------------------------------
void t_dialog_booty::restore( t_drag_artifact_source* source )
{
	m_current_drag_index = -1;
	update_booty_display();
}

// ---------------------------------------------------------------------------
// Called by t_drag_artifact_source when artifact display may need refreshing
// ---------------------------------------------------------------------------
void t_dialog_booty::update_artifacts()
{
	update_booty_display();
}

// -----------------------------------------------------------------------
// Called by t_drag_artifact_source when drag is complete
// -----------------------------------------------------------------------
void t_dialog_booty::artifact_accepted( t_drag_artifact_source * source, t_window * target )
{
	if ( m_current_drag_index >= 0 )
	{
		m_booty.erase( m_booty.begin() + m_current_drag_index );
		m_current_drag_index = -1;
		update_booty_display();
	}
}

